package by.bsu.fami.greyscalecodefrontend.activities;

import java.io.File;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.Images.Media;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import by.bsu.fami.greyscalecodefrontend.R;
import by.bsu.fami.greyscalecodefrontend.utils.GreyscaleMaker;
import by.bsu.fami.greyscalecodelibrary.GreysacleCodeLibrary;
import by.bsu.fami.greyscalecodelibrary.GreysacleCodeLibrary.DecodeResult;
import by.bsu.fami.greyscalecodelibrary.NotFoundException;
import by.bsu.fami.greyscalecodelibrary.android.GCLibAndroid8;

public class DecodeActivity extends Activity {

	private static final int DIALOG_NO_CAMERA = 200;
	private static final int DIALOG_PROGRESS = 201;
	private static final int DIALOG_NOT_FOUND = 202;
	private static final int DIALOG_ERROR = 203;
	private static final int PICK_PICTURE_GALLERY = 100;
	private static final int CAPTURE_IMAGE = 101;
	public static final String MODE = "mode";
	private static final String TAG = "DecodeActivity";

	private Uri mFileUri;
	private Mode mMode; 
	private ImageView mImageView;
	private Bitmap mBitmap;


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_decode);

		Mode modeFromIntent = (Mode) getIntent().getSerializableExtra(MODE);
		mMode = modeFromIntent == null ? Mode.USE_CAMERA : modeFromIntent;
		Log.i(TAG, "Mode " + mMode);
		setupUI();
		if (mBitmap == null) {
			selectNewImage();
		}
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		deleteImageFile();
	}
	

	private void setupUI() {
		Button decodeButton = (Button) findViewById(R.id.buttonOpenImage);
		if (mMode == Mode.USE_CAMERA) {
			decodeButton.setText(R.string.camera);
		} else {
			decodeButton.setText(R.string.gallery);
		}
		mImageView = (ImageView) findViewById(R.id.imageView);
	}

	public void onOpenImageClicked(View v) {
		selectNewImage();
	}

	public void onDecodeClicked(View v) {
		if (mBitmap != null) {
			activityShowDialog(DIALOG_PROGRESS);
			new DecodeTask().execute(mBitmap);
		} else {
			Toast.makeText(this, R.string.selectImageFirst, 
					Toast.LENGTH_LONG).show();
		}
	}
	
	@Override
	protected void onActivityResult(int requestCode, 
		int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode == RESULT_OK) {
			Uri chosenImageUri;
			if (requestCode == PICK_PICTURE_GALLERY){		       
		        try {
		        	chosenImageUri = data.getData();
					mBitmap = Media.getBitmap(this.getContentResolver(), 
							chosenImageUri);
				} catch (Exception e) {
					Log.e(TAG, "", e);
					Toast.makeText(this, R.string.failedToOpenImage, 
							Toast.LENGTH_LONG).show();
				} 
			} else if (requestCode == CAPTURE_IMAGE) {
				chosenImageUri = mFileUri;
				mBitmap = BitmapFactory.decodeFile(chosenImageUri.getPath());
			}
			if (mBitmap != null) {
				mImageView.setImageBitmap(mBitmap);
			}
		} else {
			Log.w(TAG, "onActivityResult returned error");
		}
	}

	@SuppressWarnings("deprecation")
	@Override
	protected Dialog onCreateDialog(int id) {
		
		switch (id) {
		case DIALOG_NO_CAMERA:
			return createNoCameraDialog();
		case DIALOG_PROGRESS:
			return createProgressDialog();
		case DIALOG_NOT_FOUND:
			return createWarningDialogWithTitle(
				getString(R.string.noCodeFound));
		case DIALOG_ERROR:
			return createWarningDialogWithTitle(
					getString(R.string.errorDuringDecode));
		default:
			return super.onCreateDialog(id);
		}
	}
	
	@SuppressWarnings("deprecation")
	/*default*/ void onTaskFinished(DecodeTaskResult result) {
		dismissDialog(DIALOG_PROGRESS);
		if (result.getResult() != null) {
			String text = (result.getResult().getText() == null)? 
				getString(R.string.binaryData): result.getResult().getText();
			Intent intent = new Intent(this, ResultActivity.class);
			intent.putExtra(ResultActivity.TEXT_TO_SHOW, text);
			startActivity(intent);
		} else {
			Log.w(TAG, "Error during decode. " + 
				result.getException().getMessage());
			if (result.getException() instanceof NotFoundException) {
				activityShowDialog(DIALOG_NOT_FOUND);
			} else {
				activityShowDialog(DIALOG_ERROR);
			}
		}
	}

	private Dialog createNoCameraDialog() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage(R.string.youHaveNoCamera);
		builder.setTitle(android.R.string.dialog_alert_title);
		builder.setIcon(android.R.drawable.ic_dialog_alert);
		builder.setPositiveButton(android.R.string.ok, 
				new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				finish();
			}
		});
		return builder.create();
	}
	
	private Dialog createProgressDialog() {
		ProgressDialog progressDialog = new ProgressDialog(this);
		progressDialog.setIndeterminate(true);
		return progressDialog;
	}
	
	private Dialog createWarningDialogWithTitle(String title) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage(title);
		builder.setTitle(android.R.string.dialog_alert_title);
		builder.setIcon(android.R.drawable.ic_dialog_alert);
		builder.setPositiveButton(android.R.string.ok, null);
		return builder.create();
	}

	private void selectNewImage() {
		if (mBitmap != null) {
			mBitmap.recycle();
			mBitmap = null;
		}
		if (mMode == Mode.USE_GALLERY) {
			Intent intent = new Intent(Intent.ACTION_PICK, 
					MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
			startActivityForResult(intent, PICK_PICTURE_GALLERY);
		} else if(mMode == Mode.USE_CAMERA) {
			if (checkCamera()) {
				Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
				// create a file to save the image
				deleteImageFile();
				mFileUri = getOutputUri();
				intent.putExtra(MediaStore.EXTRA_OUTPUT, mFileUri); 
				// start the image capture Intent
				startActivityForResult(intent, CAPTURE_IMAGE);
			}
		}
	}
	
	@SuppressWarnings("deprecation")
	void activityShowDialog(int id){
		showDialog(id);
	}

	private boolean checkCamera() {
		if (!getPackageManager().hasSystemFeature(
				PackageManager.FEATURE_CAMERA)) {
			activityShowDialog(DIALOG_NO_CAMERA);
			return false;
		}
		return true;
	}

	@SuppressLint("NewApi")
	@SuppressWarnings("deprecation")
	private Uri getOutputUri() {
		boolean isApi7OrLower = (Build.VERSION.SDK_INT <= 
				Build.VERSION_CODES.ECLAIR_MR1);
		File base;
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			if (!isApi7OrLower) {
				base = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
			} else {
				String packageName = getApplicationInfo().packageName;
				base = new File(Environment.getExternalStorageDirectory(),
						"/Android/data/" + packageName + "/files/Pictures/");
			}
		} else {
			Log.w(TAG, "using internal storage");
			// Aims on API level 7
			base = getDir("Pictures", MODE_WORLD_WRITEABLE);
		}

		if (!base.exists()) {
			if (!base.mkdirs()) {
				Log.e(TAG, "failed to create directory");
				return null;
			}
		}

		return Uri.fromFile(new File(base, "to_detect.jpg"));
	}
	
	private void deleteImageFile() {
		if (mFileUri != null) {
			File file = new File(mFileUri.getPath());
			boolean flag = file.delete();
			Log.i(TAG, "deletion result: " + flag);
			mFileUri = null;
		}
	}
	
	
	public static enum Mode {
		USE_CAMERA, USE_GALLERY
	}
	
	private class DecodeTaskResult {
		private DecodeResult result;
		private Exception exception;
		
		public DecodeTaskResult(DecodeResult result, Exception exception) {
			this.result = result;
			this.exception = exception;
		}
		
		public DecodeResult getResult() {
			return result;
		}
	
		public Exception getException() {
			return exception;
		}		
	}
	
	private class DecodeTask extends AsyncTask<Bitmap, Void, DecodeTaskResult> {
		
		private float[] scalesToTry = {0.25f, 0.5f, 0.1f, 1f, 0.75f};
		private int current;
		private Exception lastException;

		public DecodeTask() {}

		@Override
		protected DecodeTaskResult doInBackground(Bitmap... params) {
			current = 0;
			while (current < scalesToTry.length) {
				try {
					DecodeResult result = null;
					if (Build.VERSION.SDK_INT < 8) {
						result = GreysacleCodeLibrary.decode(
								GreyscaleMaker.scaleAndMakeGrey(
										params[0], scalesToTry[current++]));
					} else {
						current++;
						result = GCLibAndroid8.decode(params[0]);
					}
					return new DecodeTaskResult(result, null);
				} catch (Exception e) {
					Log.i(TAG, "Decode fails. Scale " + scalesToTry[current - 1] 
							+ ". " + e.getMessage());
					lastException = e;					
				}
			}
			return new DecodeTaskResult(null, lastException);
		}		
		
		@Override
		protected void onPostExecute(DecodeTaskResult result) {
			onTaskFinished(result);
		}
	}
}
